#include "graphicsscene.h"
#include <qDebug>

GraphicsScene::GraphicsScene(QObject *parent) :
    QGraphicsScene(parent)
{

}

GraphicsScene::~GraphicsScene()
{

}

bool GraphicsScene::readFile(QString& fileName)
{
    try
    {
        size_t oldSize = figureContainer.size();
        figureContainer.readFile(fileName.toStdString());
        drowFigures(figureContainer.size() - oldSize);
        return true;
    }
    catch(exceptionType err)
    {
        return false;
    }
}

bool GraphicsScene::writeFile(QString& fileName)
{
    if(scaleChanged)
    {
        saveNewScale();
        scaleChanged = false;
    }
    try
    {
        figureContainer.writeFile(fileName.toStdString());
        return true;
    }
    catch(exceptionType err)
    {
        return false;
    }
}

void GraphicsScene:: drowFigures(size_t num)
{
    if(figureContainer.size() != 0)
        for(size_t i = figureContainer.size() - num; i < figureContainer.size(); ++i)
        {
            std::vector<double> coord = figureContainer[i]->getCoord();
            if(figureContainer[i]->type() == rectangle)
            {
                figureItem = addRect(((coord[0] < coord[2]) ? coord[0] : coord[2]),
                                   ((coord[1] < coord[3]) ? coord[1] : coord[3]),
                                   abs(coord[0] - coord[2]),
                                   abs(coord[1] - coord[3]),
                                   QPen(QBrush(Qt::darkRed), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin),
                                   QBrush(Qt::red));
                std::pair<double, double> centrePoint = figureContainer[i]->centrePoint();
                figureItem->setTransformOriginPoint(centrePoint.first, centrePoint.second);
                figureItem->setRotation(coord[4]);
            }
            if(figureContainer[i]->type() == circle)
            {
                figureItem = addEllipse(coord[0] - coord[2],
                                      coord[1] - coord[2],
                                      2*coord[2],
                                      2*coord[2],
                                      QPen(QBrush(Qt::darkBlue), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin),
                                      QBrush(Qt::blue));
                std::pair<double, double> centrePoint = figureContainer[i]->centrePoint();
                figureItem->setTransformOriginPoint(centrePoint.first, centrePoint.second);
                figureItem->setRotation(coord[3]);
            }
            if(figureContainer[i]->type() == triangle)
            {
                trianglePolygon << QPoint(coord[0], coord[1])
                        << QPoint(coord[2], coord[3])
                        << QPoint(coord[4], coord[5]);
                figureItem = addPolygon(trianglePolygon,
                                      QPen(QBrush(Qt::darkGreen), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin),
                                      QBrush(Qt::green));
                std::pair<double, double> centrePoint = figureContainer[i]->centrePoint();
                figureItem->setTransformOriginPoint(centrePoint.first, centrePoint.second);
                figureItem->setRotation(coord[6]);
                trianglePolygon.clear();
            }
            figureItem->setFlag(QGraphicsItem::ItemIsSelectable);
            interpreterMap[figureItem] = i;
        }
}

void GraphicsScene::clearPicture()
{
    clear();
    figureContainer.clear();
    interpreterMap.clear();
    curentSelectedFiguresNum.clear();
    curentSelectedFiguresItems.clear();
}

void GraphicsScene::saveNewScale()
{
    for(int i = 0; i < curentSelectedFiguresNum.size(); ++i)
    {
        figureContainer[curentSelectedFiguresNum[i]]->extansion(newScale);
    }
}

void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if(drowModeFlag)
    {
        if(triangleModeFlag)
        {
            if(trianglePolygon.isEmpty())
            {
                trianglePolygon << QPoint(event->scenePos().x(), event->scenePos().y());
                lineItem = addLine(trianglePolygon.first().x(),
                                       trianglePolygon.first().y(),
                                       event->scenePos().x(),
                                       event->scenePos().y(),
                                       QPen(QBrush(Qt::darkGreen), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
            }
            else
            {
                trianglePolygon.pop_back();
                trianglePolygon << QPoint(event->scenePos().x(), event->scenePos().y());
                removeItem(figureItem);
                figureItem = addPolygon(trianglePolygon,
                                      QPen(QBrush(Qt::darkGreen), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin),
                                      QBrush(Qt::green));
                figureItem->setFlag(QGraphicsItem::ItemIsSelectable);
            }
        }
        else
        {
            centrePoint.setX(event->scenePos().x());
            centrePoint.setY(event->scenePos().y());
            if(circleModeFlag)
                figureItem = addEllipse(centrePoint.x(),
                                      centrePoint.y(),
                                      1,
                                      1,
                                      QPen(QBrush(Qt::darkBlue), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin),
                                      QBrush(Qt::blue));
            if(rectangleModeFlag)
                figureItem = addRect(centrePoint.x(),
                                   centrePoint.y(),
                                   1,
                                   1,
                                   QPen(QBrush(Qt::darkRed), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin),
                                   QBrush(Qt::red));
        }
    }
    if(selectModeFlag)
    {
        selectionArea << event->scenePos()
                      << QPointF(event->scenePos().x() + 1, event->scenePos().y())
                      << QPointF(event->scenePos().x() + 1, event->scenePos().y() + 1)
                      << QPointF(event->scenePos().x(), event->scenePos().y() + 1);

        dashItem = addPolygon(selectionArea,
                                         QPen(Qt::black, 2, Qt::DashLine, Qt::RoundCap, Qt::RoundJoin),
                                         QBrush(Qt::NoBrush));
    }
    if(shiftModeFlag)
    {
        centrePoint.setX(event->scenePos().x());
        centrePoint.setY(event->scenePos().y());
        emit signalShiftPress();
    }
    event->accept();
}

void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{    
    if(drowModeFlag)
    {
        if(triangleModeFlag)
        {
            if(trianglePolygon.size() == 1)
            {
                removeItem(lineItem);
                lineItem = addLine(trianglePolygon.first().x(),
                                       trianglePolygon.first().y(),
                                       event->scenePos().x(),
                                       event->scenePos().y(),
                                       QPen(QBrush(Qt::darkGreen), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
            }
            if(trianglePolygon.size() == 3)
            {
                trianglePolygon.pop_back();
                trianglePolygon << QPoint(event->scenePos().x(), event->scenePos().y());
                removeItem(figureItem);
                figureItem = addPolygon(trianglePolygon,
                                      QPen(QBrush(Qt::darkGreen), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin),
                                      QBrush(Qt::green));
            }
        }
        else
        {
            int a = event->scenePos().x() - centrePoint.x();
            int b = event->scenePos().y() - centrePoint.y();
            if(circleModeFlag)
            {
                R = sqrt(a*a + b*b);
                (static_cast<QGraphicsEllipseItem*>(figureItem))->setRect(centrePoint.x() - R,
                                                                        centrePoint.y() - R,
                                                                        2 * R,
                                                                        2 * R);
            }
            if(rectangleModeFlag)
                (static_cast<QGraphicsEllipseItem*>(figureItem))->setRect(centrePoint.x() + ((a < 0) ? a : 0),
                                                                        centrePoint.y() + ((b < 0) ? b : 0),
                                                                        (a < 0) ? -a : a,
                                                                        (b < 0) ? -b : b);
        }
    }
    if(selectModeFlag)
    {
        QPointF crossPoint(selectionArea[0].x(), event->scenePos().y());
        selectionArea[2] = event->scenePos();
        selectionArea[3] = crossPoint;
        crossPoint.setX(event->scenePos().x());
        crossPoint.setY(selectionArea[0].y());
        selectionArea[1] = crossPoint;

        dashItem->setPolygon(selectionArea);
    }
    if(shiftModeFlag)
    {
        for(int i = 0; i < curentSelectedFiguresNum.size(); ++i)
        {
            figureContainer[curentSelectedFiguresNum[i]]->shift(event->scenePos().x() - centrePoint.x(),
                                                                event->scenePos().y() - centrePoint.y());
            curentSelectedFiguresItems[i]->setPos(curentSelectedFiguresItems[i]->pos() + QPointF(event->scenePos().x() - centrePoint.x(),
                                                                                                      event->scenePos().y() - centrePoint.y()));
        }
        centrePoint.setX(event->scenePos().x());
        centrePoint.setY(event->scenePos().y());
    }
    event->accept();
}

void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if(drowModeFlag)
    {
        if(triangleModeFlag)
        {
            if(trianglePolygon.size() == 3)
            {
                std::vector<double> data = {static_cast<double>(trianglePolygon[0].x()),static_cast<double>(trianglePolygon[0].y()),
                                            static_cast<double>(trianglePolygon[1].x()),static_cast<double>(trianglePolygon[1].y()),
                                            static_cast<double>(trianglePolygon[2].x()),static_cast<double>(trianglePolygon[2].y()), 0};
                figureContainer.addFigure(Figure::makeFigure(triangle, data));
                trianglePolygon.clear();
                interpreterMap[figureItem] = figureContainer.size() - 1;
                std::pair<double, double> centrePoint = figureContainer[figureContainer.size() - 1]->centrePoint();
                figureItem->setTransformOriginPoint(centrePoint.first, centrePoint.second);
                figureItem->setFlag(QGraphicsItem::ItemIsSelectable);
            }
            if(trianglePolygon.size() == 1)
            {
                removeItem(lineItem);
                trianglePolygon << QPoint(event->scenePos().x(), event->scenePos().y());
                trianglePolygon << QPoint(event->scenePos().x(), event->scenePos().y());
                figureItem = addPolygon(trianglePolygon,
                                      QPen(QBrush(Qt::darkGreen), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin),
                                      QBrush(Qt::green));
            }
        }
        if(circleModeFlag)
        {
            std::vector<double> data = {static_cast<double>(centrePoint.x()), static_cast<double>(centrePoint.y()), static_cast<double>(R), 0};
            figureContainer.addFigure(Figure::makeFigure(circle, data));
            interpreterMap[figureItem] = figureContainer.size() - 1;
            figureItem->setTransformOriginPoint(centrePoint);
            figureItem->setFlag(QGraphicsItem::ItemIsSelectable);
        }
        if(rectangleModeFlag)
        {
            std::vector<double> data = {static_cast<double>(centrePoint.x()), static_cast<double>(centrePoint.y()),
                                        static_cast<double>(event->scenePos().x()), static_cast<double>(event->scenePos().y()), 0};
            figureContainer.addFigure(Figure::makeFigure(rectangle, data));
            interpreterMap[figureItem] = figureContainer.size() - 1;
            figureItem->setTransformOriginPoint((centrePoint.x() + event->scenePos().x()) / 2,
                                                (centrePoint.y() + event->scenePos().y()) / 2);
            figureItem->setFlag(QGraphicsItem::ItemIsSelectable);
        }
    }
    if(selectModeFlag)
    {
        removeItem(dashItem);

        QPainterPath path;
        path.addPolygon(selectionArea);
        setSelectionArea(path);

        curentSelectedFiguresItems = items(selectionArea);
        foreach(QGraphicsItem* item, curentSelectedFiguresItems)
        {
            curentSelectedFiguresNum.push_back(interpreterMap[item]);
        }

        if(!curentSelectedFiguresNum.isEmpty())
        {
            slotActionMode();
            emit signalActionMode(curentSelectedFiguresNum.size());
        }

        selectionArea.clear();
    }
    if(shiftModeFlag)
    {
        emit signalShiftRelease();
    }
    event->accept();
}

void GraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    event->accept();
}

void GraphicsScene::slotRotationValue(int value)
{
    for(int i = 0; i < curentSelectedFiguresNum.size(); ++i)
    {
        figureContainer[curentSelectedFiguresNum[i]]->rotation(value);
        curentSelectedFiguresItems[i]->setRotation(value);
    }
}

void GraphicsScene::slotExtansionValue(int value)
{
    scaleChanged = true;
    newScale = static_cast<double>(value) / 100;
    if(newScale != 0)
        for(int i = 0; i < curentSelectedFiguresNum.size(); ++i)
        {
            curentSelectedFiguresItems[i]->setScale(newScale);
        }
}

void GraphicsScene::slotRectangleMode()
{
    rectangleModeFlag = true;
    circleModeFlag = false;
    triangleModeFlag = false;
    if(!trianglePolygon.isEmpty())
    {
        trianglePolygon.clear();
        removeItem(figureItem);
    }
}

void GraphicsScene::slotCircleMode()
{
    rectangleModeFlag = false;
    circleModeFlag = true;
    triangleModeFlag = false;
    if(!trianglePolygon.isEmpty())
    {
        trianglePolygon.clear();
        removeItem(figureItem);
    }
}

void GraphicsScene::slotTriangleMode()
{
    rectangleModeFlag = false;
    circleModeFlag = false;
    triangleModeFlag = true;
}

void GraphicsScene::slotDrowMode()
{
    if(scaleChanged)
    {
        saveNewScale();
        scaleChanged = false;
    }
    if(!(drowModeFlag || selectModeFlag))
    {
        interpreterMap.clear();
        clear();
        drowFigures(figureContainer.size());
    }
    drowModeFlag = true;
    selectModeFlag = false;
    shiftModeFlag = false;
    setSelectionArea(QPainterPath());
    curentSelectedFiguresNum.clear();
    curentSelectedFiguresItems.clear();
}

void GraphicsScene::slotSelectMode()
{
    if(scaleChanged)
    {
        saveNewScale();
        scaleChanged = false;
    }
    if(!(drowModeFlag || selectModeFlag))
    {
        interpreterMap.clear();
        clear();
        drowFigures(figureContainer.size());
    }
    if(!trianglePolygon.isEmpty())
    {
        trianglePolygon.clear();
        removeItem(figureItem);
    }
    drowModeFlag = false;
    selectModeFlag = true;
    shiftModeFlag = false;
    setSelectionArea(QPainterPath());
    curentSelectedFiguresNum.clear();
    curentSelectedFiguresItems.clear();
}

void GraphicsScene::slotActionMode()
{
    drowModeFlag = false;
    selectModeFlag = false;
}

void GraphicsScene::slotShiftMode()
{
    shiftModeFlag = true;
}

void GraphicsScene::slotRotationMode()
{
    shiftModeFlag = false;
}

void GraphicsScene::slotExtensionMode()
{
    shiftModeFlag = false;
}
